﻿#include "opencv.hpp"

void MyEllipse(cv::Mat img, double angle, int width, int height);
void MyFilledCircle(cv::Mat img, cv::Point center, int width);
void MyPolygon(cv::Mat img, int width, int height);
void MyLine(cv::Mat img, cv::Point start, cv::Point end);

void plotLearn(cv::Mat atom_image, cv::Mat rook_image, int width, int height) {
    MyEllipse(atom_image, 90, width, height);
    MyEllipse(atom_image, 0, width, height);
    MyEllipse(atom_image, 45, width, height);
    MyEllipse(atom_image, -45, width, height);

    MyFilledCircle(atom_image, cv::Point(width / 2, height / 2), width);

    MyPolygon(rook_image, width, height);

    cv::rectangle(rook_image,
        cv::Point(0, 7 * height / 8),
        cv::Point(width, height),
        cv::Scalar(255, 0, 0),
        cv::FILLED,
        cv::LINE_8);

    MyLine(rook_image, cv::Point(0, 15 * height / 16), cv::Point(width, 15 * height / 16));
    MyLine(rook_image, cv::Point(width / 4, 7 * height / 8), cv::Point(width / 4, height));
    MyLine(rook_image, cv::Point(width / 2, 7 * height / 8), cv::Point(width / 2, height));
    MyLine(rook_image, cv::Point(3 * width / 4, 7 * height / 8), cv::Point(3 * width / 4, height));
}


void MyEllipse(cv::Mat img, double angle, int width, int height)
{
    int thickness = 2;
    int lineType = 8;

    cv::ellipse(img,
        cv::Point(width / 2, height / 2),
        cv::Size(width / 4, height / 16),
        angle,
        0,
        360,
        cv::Scalar(255, 0, 255),
        thickness,
        lineType);
}

void MyFilledCircle(cv::Mat img, cv::Point center, int width)
{
    cv::circle(img,
        center,
        width / 32,
        cv::Scalar(0, 0, 255),
        cv::FILLED,
        cv::LINE_8);
}

void MyPolygon(cv::Mat img, int width, int height)
{
    int lineType = cv::LINE_8;

    cv::Point rook_points[1][20];
    rook_points[0][0] = cv::Point(width / 4, 7 * height / 8);
    rook_points[0][1] = cv::Point(3 * width / 4, 7 * height / 8);
    rook_points[0][2] = cv::Point(3 * width / 4, 13 * height / 16);
    rook_points[0][3] = cv::Point(11 * width / 16, 13 * height / 16);
    rook_points[0][4] = cv::Point(19 * width / 32, 3 * height / 8);
    rook_points[0][5] = cv::Point(3 * width / 4, 3 * height / 8);
    rook_points[0][6] = cv::Point(3 * width / 4, height / 8);
    rook_points[0][7] = cv::Point(26 * width / 40, height / 8);
    rook_points[0][8] = cv::Point(26 * width / 40, height / 4);
    rook_points[0][9] = cv::Point(22 * width / 40, height / 4);
    rook_points[0][10] = cv::Point(22 * width / 40, height / 8);
    rook_points[0][11] = cv::Point(18 * width / 40, height / 8);
    rook_points[0][12] = cv::Point(18 * width / 40, height / 4);
    rook_points[0][13] = cv::Point(14 * width / 40, height / 4);
    rook_points[0][14] = cv::Point(14 * width / 40, height / 8);
    rook_points[0][15] = cv::Point(width / 4, height / 8);
    rook_points[0][16] = cv::Point(width / 4, 3 * height / 8);
    rook_points[0][17] = cv::Point(13 * width / 32, 3 * height / 8);
    rook_points[0][18] = cv::Point(5 * width / 16, 13 * height / 16);
    rook_points[0][19] = cv::Point(width / 4, 13 * height / 16);

    const cv::Point* ppt[1] = { rook_points[0] };
    int npt[] = { 20 };

    cv::fillPoly(img,
        ppt,
        npt,
        1,
        cv::Scalar(255, 255, 255),
        lineType);
}

void MyLine(cv::Mat img, cv::Point start, cv::Point end)
{
    int thickness = 2;
    int lineType = cv::LINE_8;

    cv::line(img,
        start,
        end,
        cv::Scalar(255, 255, 255),
        thickness,
        lineType);
}

static cv::Scalar randomColor(cv::RNG& rng)
{
    int icolor = (unsigned)rng;
    return cv::Scalar(icolor & 255, (icolor >> 8) & 255, (icolor >> 16) & 255);
}

void randomLearn(cv::Mat img01, cv::Mat img02, cv::Mat img03, int width, int height) {
    cv::RNG rng(0xFFFFFFFF);
    cv::ellipse(
        img01,
        cv::Point(width / 2, height / 2),
        cv::Size(rng.uniform(height / 8, height * 3 / 8), rng.uniform(width / 8, width * 3 / 8)),
        rng.uniform(0, 360),
        rng.uniform(0, 90),
        rng.uniform(180, 360),
        randomColor(rng));
    cv::line(
        img02,
        cv::Point(rng.uniform(width / 8, width * 3 / 8), rng.uniform(height / 2, height * 7 / 8)),
        cv::Point(rng.uniform(width / 8, width * 3 / 8), rng.uniform(height / 2, height * 7 / 8)),
        randomColor(rng));
    cv::rectangle(
        img03,
        cv::Point(rng.uniform(0, width / 2), rng.uniform(0, height / 2)),
        cv::Point(rng.uniform(width / 2, width), rng.uniform(height / 2, height)),
        randomColor(rng));
    cv::Point org01(rng.uniform(width / 4, width / 2), rng.uniform(height / 4, height / 2));
    putText(img01, "ellipse", org01, rng.uniform(0, 8),
        rng.uniform(0, 10) * 0.05 + 0.5, randomColor(rng));
    cv::Point org02(rng.uniform(width / 4, width / 2), rng.uniform(height / 4, height / 2));
    putText(img02, "line", org02, rng.uniform(0, 8),
        rng.uniform(0, 10) * 0.05 + 0.5, randomColor(rng));
    cv::Point org03(rng.uniform(width / 4, width / 2), rng.uniform(height / 4, height / 2));
    putText(img03, "rectangle", org03, rng.uniform(0, 8),
        rng.uniform(0, 10) * 0.05 + 0.5, randomColor(rng));
}

void filterLearn(cv::Mat& imgSrc, cv::Mat& imgDst, int filterId, int kernelSize) {
    switch (filterId)
    {
        case 0: // blur
            cv::blur(imgSrc, imgDst, cv::Size(kernelSize, kernelSize));
            break;
        case 1: // GaussianBlur
			cv::GaussianBlur(imgSrc, imgDst, cv::Size(kernelSize, kernelSize), 0);
            break;
        case 2: // medianBlur
            cv::medianBlur(imgSrc, imgDst, kernelSize);
			break;
        case 3: // bilateralFilter
            cv::bilateralFilter(imgSrc, imgDst, 5, static_cast<double>(kernelSize) * 2, static_cast<double>(kernelSize) / 2);
			break;
        default:
            imgDst = imgSrc.clone();
            break;
    }
}

void ErosionOrDilation(cv::Mat& src, cv::Mat& dst, int shape, cv::Size ksize, cv::Point anchor, bool ChooseErosion) {
    cv::Mat element = cv::getStructuringElement(shape, ksize, anchor);

    if(ChooseErosion) erode(src, dst, element);
    else dilate(src, dst, element);
}
